﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using HB.MVVM;
using System.Windows.Forms;
using System.IO;
using System.Collections.ObjectModel;
using System.Windows;
using LiveCharts.Geared;
using System.Windows.Input;
using HB.Base;
using System.Collections.Concurrent;

namespace DiskWatch
{
    public class VMMainWindow : ViewModelBase
    {
        public Action<bool> ChangeTopMost;
        public Action<string> Log;
        AverageSpeed SpeedRenameCal = new AverageSpeed(2);
        AverageSpeed SpeedCreateCal = new AverageSpeed(2);
        AverageSpeed SpeedDeleteCal = new AverageSpeed(2);
        AverageSpeed SpeedChangedCal = new AverageSpeed(2);
        public VMMainWindow()
        {
            RegisterChangedEvent(nameof(TopMost), () =>
            {
                ChangeTopMost.Invoke(TopMost);
            });
        }
        public override void VM_Init(object sender, RoutedEventArgs e)
        {
            IocResolve(out ChangeTopMost);
            SpeedChangedCal.OnSpeedChanged += d => SpeedChanged = $"{d.ToString("f1")}/s";
            Watch.Changed += (a, b) =>
            {
                changedTemp += 1;
                SpeedChangedCal.Log();
                if (IsShowChangedPath)
                {
                    Log?.Invoke($"{DateTime.Now.ToString("HH:mm:ss")} Change {b.FullPath}");
                }
            };
            SpeedDeleteCal.OnSpeedChanged += d => SpeedDelete = $"{d.ToString("f1")}/s";
            Watch.Deleted += (a, b) =>
            {
                SpeedDeleteCal .Log();
                deleteTemp += 1;
                if (IsShowDeletedPath)
                {
                    Log?.Invoke($"{DateTime.Now.ToString("HH:mm:ss")} Delete {b.FullPath}");
                }
            };
            SpeedCreateCal.OnSpeedChanged += d => SpeedCreate = $"{d.ToString("f1")}/s";
            Watch.Created += (a, b) =>
            {
                SpeedCreateCal .Log();
                createTemp += 1;
                if (IsShowCreatedPath)
                {
                    Log?.Invoke($"{DateTime.Now.ToString("HH:mm:ss")} Create {b.FullPath}");
                }
            };
            SpeedRenameCal.OnSpeedChanged += d => SpeedRename = $"{d.ToString("f1")}/s";
            Watch.Renamed += (a, b) =>
            {
                SpeedRenameCal.Log();
                renameTemp += 1;
                if (IsShowRenamePath)
                {
                    Log?.Invoke($"{DateTime.Now.ToString("HH:mm:ss")} ReName {b.FullPath}");
                }
            };

            Log = s =>
            {
                LogBuffer.Enqueue(s);
            };
        }

        public bool TopMost { get => GetBool(); set => Set(value); }
        public int ChangedNum { get => GetInt(); set => Set(value); }
        public bool ShowChanged { get => GetBool(true); set => Set(value); }
        public string SpeedChanged { get => GetString(); set => Set(value); }
        int changedTemp { get; set; }
        public bool IsShowChangedPath { get => GetBool(); set => Set(value); }
        public int DeletedNum { get => GetInt(); set => Set(value); }
        public bool ShowDelete { get => GetBool(true); set => Set(value); }
        public string SpeedDelete { get => GetString(); set => Set(value); }
        int deleteTemp { get; set; }
        public bool IsShowDeletedPath { get => GetBool(); set => Set(value); }
        public int CreatedNum { get => GetInt(); set => Set(value); }
        public bool ShowCreate { get => GetBool(true); set => Set(value); }
        public string SpeedCreate { get => GetString(); set => Set(value); }
        int createTemp { get; set; }
        public bool IsShowCreatedPath { get => GetBool(); set => Set(value); }
        public int RenameNum { get => GetInt(); set => Set(value); }
        public bool ShowRename { get => GetBool(true); set => Set(value); }
        public string SpeedRename { get => GetString(); set => Set(value); }
        int renameTemp { get; set; }
        public bool IsShowRenamePath { get => GetBool(); set => Set(value); }
        public bool IsRunning { get => GetBool(); set => Set(value); }

        FileSystemWatcher Watch { get; set; } = new FileSystemWatcher();
        public ObservableCollection<string> LogList { get; set; } = new ObservableCollection<string>();
        public ConcurrentQueue<string> LogBuffer { get; set; } = new ConcurrentQueue<string>();
        public string SelectedDisk { get => GetString(); set => Set(value); }

        public GearedValues<int> ChartChanged { get; set; } = new GearedValues<int>();
        public GearedValues<int> ChartDeleted { get; set; } = new GearedValues<int>();
        public GearedValues<int> ChartCreated { get; set; } = new GearedValues<int>();
        public GearedValues<int> ChartRename { get; set; } = new GearedValues<int>();
        TriggerTimer trigger = new TriggerTimer();
        public ICommand cmdSelectPath => GetCommand(() =>
        {
            FolderBrowserDialog fd = new FolderBrowserDialog();
            if (fd.ShowDialog() == DialogResult.OK)
            {
                SelectedDisk = fd.SelectedPath;
            }
        });
        public ICommand cmdStart => GetCommand(() =>
        {
            if (!Directory.Exists(SelectedDisk)) { return; }
            Watch.EnableRaisingEvents = false;
            Watch.IncludeSubdirectories = true;
            Watch.Path = SelectedDisk;
            Watch.EnableRaisingEvents = true;
            if (IsRunning == false)
            {
                IsRunning = true;
                trigger.Start(2, (t, i) =>
                {
                    ChangedNum += changedTemp;
                    ChartChanged.Add(changedTemp);
                    if (ChartChanged.Count > 100) { ChartChanged.RemoveAt(0); }
                    changedTemp = 0;

                    RenameNum += renameTemp;
                    ChartRename.Add(renameTemp);
                    if (ChartRename.Count > 100) { ChartRename.RemoveAt(0); }
                    renameTemp = 0;

                    CreatedNum += createTemp;
                    ChartCreated.Add(createTemp);
                    if (ChartCreated.Count > 100) { ChartCreated.RemoveAt(0); }
                    createTemp = 0;

                    DeletedNum += deleteTemp;
                    ChartDeleted.Add(deleteTemp);
                    if (ChartDeleted.Count > 100) { ChartDeleted.RemoveAt(0); }
                    deleteTemp = 0;

                    if (LogBuffer.Count > 0)
                    {
                        System.Windows.Application.Current.Dispatcher.BeginInvoke(new Action(() =>
                        {
                            for (int ii = 0; ii < LogBuffer.Count; ii++)
                            {
                                if (LogList.Count > 100) { LogList.RemoveAt(99); }
                                if (LogBuffer.TryDequeue(out string path))
                                {
                                    LogList.Insert(0, path);
                                }

                            }
                        }));
                    }
                });
            }


        });
        public ICommand cmdStop => GetCommand(() =>
        {
            Watch.EnableRaisingEvents = false;
            IsRunning = false;
            trigger.Stop();
        });
        public ICommand cmdClear => GetCommand(() =>
        {
            ChartChanged.Clear();
            ChartCreated.Clear();
            ChartRename.Clear();
            ChartDeleted.Clear();

            ChangedNum = 0;
            DeletedNum = 0;
            RenameNum = 0;
            CreatedNum = 0;
            LogList.Clear();
        });
    }
}
